package com.hnust.root.web.shiro;

import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.hnust.root.common.util.JWTUtil;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/**
 * 为小程序用户设置的realm
 */
@Component
public class WXJWTRealm {

    private static final Log LOGGER = LogFactory.get();

    @Autowired
    private JWTUtil jwtUtil;

    /**
     * 配置所有自定义的realm,方便起见,应对可能有多个realm的情况
     */
    public List<Realm> allRealm() {
        List<Realm> realmList = new LinkedList<>();
        AuthorizingRealm jwtRealm = jwtRealm();
        realmList.add(jwtRealm);
        return Collections.unmodifiableList(realmList);
    }

    private AuthorizingRealm jwtRealm() {
        AuthorizingRealm jwtRealm = new AuthorizingRealm() {
            /**
             * 必须重写此方法，不然Shiro会报错
             */
            @Override
            public boolean supports(AuthenticationToken token) {
                return token instanceof JWTToken;
            }

            @Override
            protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
                return new SimpleAuthorizationInfo();
            }

            /**
             * 校验token逻辑
             *
             * @param token
             * @return
             * @throws AuthenticationException
             */
            @Override
            protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
                String jwtToken = (String) token.getCredentials();
                String wxOpenId = jwtUtil.getOpenIdByWxToken(jwtToken);
                String sessionKey = jwtUtil.getSessionKeyByWxToken(jwtToken);
                if (StrUtil.isEmpty(wxOpenId) || StrUtil.isEmpty(sessionKey)) {
                    throw new AuthenticationException("账户不存在");
                }
                if (!jwtUtil.wxTokenVerify(jwtToken)) {
                    throw new AuthenticationException("token 无效，请检查token");
                }
                //后续还应该在这从数据库中判断用户是否被禁用等等
                return new SimpleAuthenticationInfo(wxOpenId, sessionKey,"wx_realm");
            }
        };
        jwtRealm.setCredentialsMatcher(credentialsMatcher());
        return jwtRealm;
    }
    /**
     * 坑点，密码校验，因为是JWT格式，就无须密码校验和加密，直接让其返回true,如果没有，那么会是false,即始终不会校验通过
     *
     * @return
     */
    private CredentialsMatcher credentialsMatcher() {
        return (token, info) -> true;
    }
}
